圖書管理系統完成書籍的 CRUD 之後,接下來要面對的就是使用者。
要做借還書功能,系統必須先知道「是誰借了這本書」。因此,需要一套會員機制。今天先把「會員註冊」建立起來。
如果資料庫直接存明文,會有以下問題:
觀念釐清後,在專案目錄下啟動 Claude Code,下達以下 Prompt:
請幫我寫一個 register.php。前端要包含帳號與密碼表單,後端接收 POST 請求後,要檢查欄位是否為空、確認帳號有沒有重複。最重要的是,密碼必須使用 password_hash() 處理後,才能寫入 members 資料表。
生成的register.php
} elseif ($password !== $passwordConfirm) {
$errors[] = '兩次輸入的密碼不一致'; // 兩次密碼輸入不同
}
// ------------------------------------------------------------
// 子區塊:檢查帳號是否已被註冊(重複帳號)
// ------------------------------------------------------------
if (empty($errors)) { // 前面欄位驗證都通過才查資料庫,避免無意義的查詢
$checkSql = 'SELECT id FROM members WHERE email = :email'; // 依 email 查詢是否已存在
$checkStmt = $pdo->prepare($checkSql); // 準備查詢語句
$checkStmt->execute([':email' => $email]); // 綁定帳號並執行查詢
if ($checkStmt->fetch() !== false) { // 查到資料代表帳號已存在
$errors[] = '這個帳號已經被註冊,請改用其他 email'; // 加入重複帳號錯誤訊息
}
}
// ------------------------------------------------------------
// 子區塊:驗證通過後,雜湊密碼並寫入 members 資料表
// ------------------------------------------------------------
if (empty($errors)) {
$passwordHash = password_hash($password, PASSWORD_DEFAULT); // 用 password_hash() 產生安全的密碼雜湊,絕不儲存明文密碼
try {
$insertSql = 'INSERT INTO members (name, email, password) VALUES (:name, :email, :password)'; // role 使用資料表預設值 member
$insertStmt = $pdo->prepare($insertSql); // 準備新增語句
$insertStmt->execute([
':name' => $name, // 綁定姓名
':email' => $email, // 綁定帳號
':password' => $passwordHash, // 綁定雜湊後的密碼
]);
header('Location: index.php'); // 註冊成功導回首頁
exit; // 導向後立刻結束,避免下方 HTML 繼續輸出
} catch (PDOException $e) {
if ($e->getCode() === '23000') { // 23000 為唯一鍵衝突,理論上前面已檢查過,這裡是防止併發情境下的極端情況
$errors[] = '這個帳號已經被註冊,請改用其他 email';
} else {
$errors[] = '註冊失敗,請稍後再試'; // 其他資料庫錯誤,不把細節暴露給使用者
}
}
}
}
?>
<!DOCTYPE html>
<html lang="zh-Hant">
<head>
<meta charset="UTF-8">
<title>會員註冊 - 圖書管理系統</title>
<style>
body {
font-family: "Microsoft JhengHei", Arial, sans-serif;
background-color: #f5f5f5;
color: #333;
margin: 0;
padding: 2rem;
}
h1 {
text-align: center;
margin-bottom: 1.5rem;
}
form {
width: 100%;
max-width: 480px;
margin: 0 auto;
background-color: #fff;
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
padding: 1.5rem 2rem;
box-sizing: border-box;
}
.field {
margin-bottom: 1rem;
}
label {
display: block;
margin-bottom: 0.35rem;
font-weight: bold;
}
input[type="text"],
input[type="email"],
input[type="password"] {
width: 100%;
padding: 0.5rem;
border: 1px solid #ccc;
border-radius: 4px;
box-sizing: border-box;
font-size: 1rem;
}
button {
width: 100%;
padding: 0.75rem;
background-color: #2c3e50;
color: #fff;
border: none;
border-radius: 4px;
font-size: 1rem;
cursor: pointer;
}
button:hover {
background-color: #1a252f;
}
.errors {
max-width: 480px;
margin: 0 auto 1rem;
background-color: #fdecea;
color: #b71c1c;
border: 1px solid #f5c6cb;
border-radius: 4px;
padding: 0.75rem 1rem;
}
.errors ul {
margin: 0;
padding-left: 1.25rem;
}
.back-link {
display: block;
max-width: 480px;
margin: 1rem auto 0;
text-align: center;
}
</style>
</head>
<body>
<h1>會員註冊</h1>
<?php // 區塊:顯示驗證或寫入錯誤訊息 ?>
<?php if (!empty($errors)): ?>
<div class="errors">
<ul>
<?php foreach ($errors as $error): ?>
<li><?= htmlspecialchars($error) ?></li>
<?php endforeach; ?>
</ul>
</div>
<?php endif; ?>
<!-- 區塊:註冊表單,欄位包含姓名、帳號(email)、密碼、確認密碼 -->
<form method="POST" action="register.php">
<div class="field">
<label for="name">姓名</label>
<input type="text" id="name" name="name" value="<?= htmlspecialchars($name) ?>" required>
</div>
<div class="field">
<label for="email">帳號 (email)</label>
<input type="email" id="email" name="email" value="<?= htmlspecialchars($email) ?>" required>
</div>
<div class="field">
<label for="password">密碼</label>
<input type="password" id="password" name="password" required>
</div>
<div class="field">
<label for="password_confirm">確認密碼</label>
<input type="password" id="password_confirm" name="password_confirm" required>
</div>
<button type="submit">註冊</button>
</form>
<a class="back-link" href="index.php">返回書籍列表</a>
</body>
</html>
index.php,且資料庫的 password 欄位會是一串雜湊碼。今天完成了會員註冊功能,並驗證了雜湊處理與資安防護。明天將實作「會員登入與 Session 狀態管理」。